/* FolderTree.cs - Daten-View Beziehung
 * Copyright (C) 2009 Dietmar Schinnerl
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */


using System;
using System.Collections.Generic;
using System.Collections;
using System.Windows.Forms;
using System.Reflection;
using System.Xml.Serialization;

namespace App.Net
{

    [Serializable]
    public class FolderTree
    {
        
        [XmlIgnore]
        private Folder folder;
        [NonSerialized()][XmlIgnore]
        public TreeView TreeView;
        private int index;
        [NonSerialized()][XmlIgnore]
        private FolderTreeNode redrawSelectedFTN;
        [NonSerialized()][XmlIgnore]
        private FolderTreeNode rightMouseButtonSelectedFTN;
        
        public FolderTree()
        {

        }

        /// 
        /// <param name="treeView"></param>
        public FolderTree(TreeView treeView)
        {
            folder = new Folder();
            this.TreeView = treeView;

            Init();

        }


        public void Redraw()
        {
            redrawSelectedFTN = (FolderTreeNode)TreeView.SelectedNode;
            TreeView.BeginUpdate();
            TreeView.Nodes.Clear();
            ArrayList folderDepth = new ArrayList();
            index = 0; // used for indexing elements during redraw
            RedrawFolders(folder, folderDepth);
            //treeTasks.ExpandAll();
            RedrawExpand(TreeView.Nodes);

            TreeView.EndUpdate();

        }

        public void AddFolder()
        {
            FolderTreeNode ftn = ((FolderTreeNode)TreeView.SelectedNode);
            Folder f;
            if (ftn == null)
                f = folder;
            else if (ftn.Folder != null)
                f = ftn.Folder;
            else
                f = ftn.ParentFolder;
            {
                Folder newFolder = new Folder();
                newFolder.Name = "New Folder";
                f.FolderList.Add(newFolder);
            }


            Redraw();

        }

        /// 
        /// <param name="folder"></param>
        /// <param name="folderDepth"></param>
        public void RedrawFolders(Folder aFolder, ArrayList folderDepth)
        {

            TreeNode n = null;

            foreach (int d in folderDepth)
            {
                if (n == null)
                    n = TreeView.Nodes[d];
                else
                    n = n.Nodes[d];
            }

            int newD = 0;
            foreach (Folder f in aFolder.FolderList)
            {
                FolderTreeNode ftn = new FolderTreeNode(f.Name, f, null, aFolder);
                // Select actual folder
                if ((redrawSelectedFTN != null) && (redrawSelectedFTN.Folder == ftn.Folder) && (redrawSelectedFTN.Name == ftn.Name) && (redrawSelectedFTN.Element == ftn.Element))
                    TreeView.SelectedNode = ftn;
                // --------------------
                if (n == null)
                    TreeView.Nodes.Add(ftn);
                else
                    n.Nodes.Add(ftn);




                folderDepth.Add(newD);
                RedrawFolders(f, folderDepth);
                folderDepth.RemoveAt(folderDepth.Count - 1);
                newD++;
            }

            foreach (Element e in aFolder.ElementList)
            {
                e.Id = ++index;
                string treeNodeText = e.Name + " (" + e.Id.ToString() + ")";
                FolderTreeNode ftn = new FolderTreeNode(treeNodeText, null, e, aFolder);
                // Select actual element
                if ((redrawSelectedFTN != null) && (redrawSelectedFTN.Folder == ftn.Folder) && (redrawSelectedFTN.Name == ftn.Name) && (redrawSelectedFTN.Element == ftn.Element))
                    TreeView.SelectedNode = ftn;
                // --------------------
                if (n == null)
                    TreeView.Nodes.Add(ftn);
                else
                    n.Nodes.Add(ftn);
            }



        }

        /// 
        /// <param name="nodes"></param>
        private void RedrawExpand(TreeNodeCollection nodes)
        {

            foreach (TreeNode node in nodes)
            {
                var folderTreeNode = node as FolderTreeNode; 
                if ((folderTreeNode != null) && (folderTreeNode.Folder != null))
                {
                    if (folderTreeNode.Folder.Expanded == true)
                    {
                        node.Expand();
                        RedrawExpand(node.Nodes);
                    }
                }
            }
        }

        private void EventAfterExpand(object sender, TreeViewEventArgs e)
        {
            ((FolderTreeNode)e.Node).Folder.Expanded = true;
        }

        private void EventAfterCollapse(object sender, TreeViewEventArgs e)
        {
            ((FolderTreeNode)e.Node).Folder.Expanded = false;
        }

        private void EventMouseDown(object sender, MouseEventArgs e)
        {
            // select the node the mouse is over through code. The select event is not fired if its the same
            // node. Only act if it's the RMB.
            /*if(e.Button != MouseButtons.Right)
            {
                return;
            }*/

            // Store the selected node (can deselect a node).
            FolderTreeNode ftn = (FolderTreeNode)TreeView.GetNodeAt(e.X, e.Y);
            if (TreeView.SelectedNode != ftn)
            {
                if (ftn != null)
                {
                    TreeView.SelectedNode = ftn;
                    rightMouseButtonSelectedFTN = ftn;
                }
                else
                    rightMouseButtonSelectedFTN = null;
            }
            else
                rightMouseButtonSelectedFTN = (FolderTreeNode)TreeView.SelectedNode;
            // set the right contextmenu with the selected node.
            //SetNodeSpecificSettings();
        }

        public virtual Folder Folder
        {
            get
            {
                return folder;
            }
            set
            {
                folder = value;
            }
        }



        /// 
        /// <param name="element"></param>
        public void AddElement(Element element)
        {
            FolderTreeNode ftn;
            if (rightMouseButtonSelectedFTN == null)
                ftn = null;
            else
                ftn = ((FolderTreeNode)TreeView.SelectedNode);
            //FolderTreeNode ftn = _rightMouseButtonSelectedFTN;
            Folder f;
            if (ftn == null)
                f = folder;
            else if (ftn.Folder != null)
                f = ftn.Folder;
            else
                f = ftn.ParentFolder;
            {
                f.ElementList.Add(element);
            }


            Redraw();

        }

        public Element Remove()
        {
            Element retVal = null;
            FolderTreeNode ftn;
            if (rightMouseButtonSelectedFTN == null)
                ftn = null;
            else
                ftn = (FolderTreeNode)TreeView.SelectedNode;
            //FolderTreeNode ftn = _rightMouseButtonSelectedFTN;
            if (ftn != null)
            {
                if (ftn.Element != null)
                {
                    ftn.ParentFolder.ElementList.Remove(ftn.Element);
                    retVal = ftn.Element;
                }
                else
                {
                    ftn.ParentFolder.FolderList.Remove(ftn.Folder);
                }
                Redraw();
            }
            return retVal;
        }



        /// 
        /// <param name="recFolder"></param>
        /// <param name="elementList"></param>
        public void CreateElementList(Folder aFolder, List<Element> elementList)
        {            
            foreach (Folder f in aFolder.FolderList)
                CreateElementList(f, elementList);
            foreach (Element element in aFolder.ElementList)
                elementList.Add(element);
        }

        /// 
        /// <param name="index"></param>
        public Element GetElement(int searchId)
        {
            var elementList=new List<Element>();
            CreateElementList(folder, elementList);
            foreach (Element element in elementList)
                if (element.Id == searchId)
                    return element;

            //if ((searchId >= 0) && (searchId < elementList.Count))
            //    return (elementList[searchId]);
            return null;
        }

        public void Init()
        {
            TreeView.AfterCollapse += new System.Windows.Forms.TreeViewEventHandler(this.EventAfterCollapse);
            TreeView.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.EventAfterExpand);
            TreeView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.EventMouseDown);

        }

        public int NrOfElements 
        {
            get
            {
                List<Element> elementList = new List<Element>();
                CreateElementList(folder, elementList);
                return elementList.Count;
            }
        }


        public void MoveUp(FolderTreeNode selectedNode)
        {
         
            if (selectedNode != null)
            {
                if (selectedNode.Element != null)
                {
                    // Element nach oben
                    int indexOfTask = selectedNode.ParentFolder.ElementList.IndexOf(selectedNode.Element);
                    if (indexOfTask > 0)
                    {
                        selectedNode.ParentFolder.ElementList.Remove(selectedNode.Element);
                        selectedNode.ParentFolder.ElementList.Insert(indexOfTask - 1, selectedNode.Element);
                        this.Redraw();
                    }
                }
                else
                {
                    // Folder nach oben
                    int indexOfTask = selectedNode.ParentFolder.FolderList.IndexOf(selectedNode.Folder);
                    if (indexOfTask > 0)
                    {
                        selectedNode.ParentFolder.FolderList.Remove(selectedNode.Folder);
                        selectedNode.ParentFolder.FolderList.Insert(indexOfTask - 1, selectedNode.Folder);
                        this.Redraw();
                    }
                }
            }
         
        }


        public void MoveDown(FolderTreeNode selectedNode)
        {
            if (selectedNode != null)
            {
                if (selectedNode.Element != null)
                {
                    // Element nach unten
                    int indexOfTask = selectedNode.ParentFolder.ElementList.IndexOf(selectedNode.Element);
                    if ((indexOfTask >= 0) && (indexOfTask < selectedNode.ParentFolder.ElementList.Count - 1))
                    {
                        selectedNode.ParentFolder.ElementList.Remove(selectedNode.Element);
                        selectedNode.ParentFolder.ElementList.Insert(indexOfTask + 1, selectedNode.Element);
                        this.Redraw();
                    }
                }
                else
                {
                    // Folder nach unten
                    int indexOfTask = selectedNode.ParentFolder.FolderList.IndexOf(selectedNode.Folder);
                    if ((indexOfTask >= 0) && (indexOfTask < selectedNode.ParentFolder.FolderList.Count - 1))
                    {
                        selectedNode.ParentFolder.FolderList.Remove(selectedNode.Folder);
                        selectedNode.ParentFolder.FolderList.Insert(indexOfTask + 1, selectedNode.Folder);
                        this.Redraw();
                    }
                }
            }
        }

    }//end FolderTree

}















































































































